// Product name: GPS/GPRS/GSM Module V3.0
// # Product SKU : TEL0051
// # Version     : 0.1
  
// # Description:
// # The sketch for driving the gps mode via the Arduino board
  
// # Steps:
// #        1. Turn the S1 switch to the Prog(right side)
// #        2. Turn the S2 switch to the Arduino side(left side)
// #        3. Take off the GSM/GPS jumper caps from the Uart select
// #        4. Upload the sketch to the Arduino board
// #        5. Turn the S1 switch to the comm(left side) 
// #        6. Remove the jumpers(old version) or set the UART select switch to middle.
// #        7. RST the board 
// #        If you get 'inf' values, go outdoors and wait until it is connected.
// #        wiki link- http://www.dfrobot.com/wiki/index.php/GPS/GPRS/GSM_Module_V3.0_(SKU:TEL0051)
//--------------------------------------------------------------------------------------------------
//function prototypes
void readTillComma(char* readBuff, boolean expectingCommaFirst = false);
void grabSerialData(char* TimeRead, 
                    char* Latitude, char* LatDir, 
                    char* Longitude,  char* LongDir,
                    char* fixQuality);
//End function prototypes
//------------------------
//most of these functions came from the website, can't remember which ones work.. and which ones don't
double Datatransfer(char *data_buf,char num)//convert the data to the float type
{                                           //*data_buf：the data array                                       
  double temp=0.0;                           //the number of the right of a decimal point
  unsigned char i,j;
   
  if(data_buf[0]=='-')
  {
    i=1;
    //process the data array
    while(data_buf[i]!='.')
      temp=temp*10+(data_buf[i++]-0x30);
    for(j=0;j<num;j++)
      temp=temp*10+(data_buf[++i]-0x30);
    //convert the int type to the float type
    for(j=0;j<num;j++)
      temp=temp/10;
    //convert to the negative numbe
    temp=0-temp;
  }
  else//for the positive number
  {
    i=0;
    while(data_buf[i]!='.')
      temp=temp*10+(data_buf[i++]-0x30);
    for(j=0;j<num;j++)
      temp=temp*10+(data_buf[++i]-0x30);
    for(j=0;j<num;j++)
      temp=temp/10 ;
  }
  return temp;
}
 
char ID()//Match the ID commands
{ 
  char i=0;
  char value[6]={
    '$','G','P','G','G','A'    };//match the gps protocol
  char val[6]={
    '0','0','0','0','0','0'    };
 
  while(1)
  {
    if(Serial.available())
    {
      val[i] = Serial.read();//get the data from the serial interface
      if(val[i]==value[i]) //Match the protocol
      {    
        i++;
        if(i==6)
        {
          i=0;
          return 1;//break out after get the command
        }
      }
      else
        i=0;
    }
  } 
}
 
void comma(char num)//get ','
{   
  char val;
  char count=0;//count the number of ','
 
  while(1)
  {
    if(Serial.available())
    {
      val = Serial.read();
      if(val==',')
        count++;
    }
    if(count==num)//if the command is right, run return
      return;
  }
 
}
void UTC()//get the UTC data -- the time
{
  char i;
  char time[9]={
    '0','0','0','0','0','0','0','0','0'
  };
  double t=0.0;
 
  if( ID())//check ID
  {
    comma(1);//remove 1 ','
    //get the datas after headers
    while(1)
    {
      if(Serial.available())
      {
        time[i] = Serial.read();
        i++;
      }
      if(i==9)
      {
        i=0;
        t=Datatransfer(time,2);//convert data
        t=t+80000.00;//convert to the chinese time GMT+8 Time zone
        Serial.println(t);//Print data 
        return;
      }  
    }
  }
}
void latitude()//get latitude
{
  char i;
  char lat[10]={
    '0','0','0','0','0','0','0','0','0','0'
  };
 

      if(Serial.available())
      {
        lat[i] = Serial.read();
        Serial.println(lat[i],DEC);
        i++;
      }

    
    
  if( ID())
  {
    //Serial.println("ID verified!");
    comma(2);
    while(1)
    {
      if(Serial.available())
      {
        lat[i] = Serial.read();
        //Serial.println(lat[i],DEC);
        i++;
      }
      if(i==10)
      {
         i=0;
         //Serial.println(lat[4]);
         //Serial.println(lat[5]);
         //Serial.println(lat[6]);
         //Serial.println(lat[7]);
         //Serial.println(lat[8]);
         Serial.println(Datatransfer(lat,5),5);//print latitude 
         return;
      }  
    }
  }
}
void lat_dir()//get dimensions
{
  char i=0,val;
 
  if( ID())
  {
    comma(3);
    while(1)
    {
      if(Serial.available())
      {
        val = Serial.read();
        Serial.write(val);
        Serial.println();
        i++;
      }
      if(i==1)
      {
        i=0;
        return;
      }  
    }
  }
}
void longitude()//get longitude
{
  char i;
  char lon[11]={
    '0','0','0','0','0','0','0','0','0','0','0'
  };
 
  if( ID())
  {
    comma(4);
    while(1)
    {
      if(Serial.available())
      {
        lon[i] = Serial.read();
        i++;
      }
      if(i==11)
      {
        i=0;
        Serial.println(Datatransfer(lon,5),5);
        return;
      }  
    }
  }
}
void lon_dir()//get direction data
{
  char i=0,val;
 
  if( ID())
  {
    comma(5);
    while(1)
    {
      if(Serial.available())
      {
        val = Serial.read();
        Serial.write(val); //Serial.println(val,BYTE);
        Serial.println();
        i++;
      }
      if(i==1)
      {
        i=0;
        return;
      }  
    }
  }
}
void altitude()//get altitude data
{
  char i,flag=0;
  char alt[8]={
    '0','0','0','0','0','0','0','0'
  };
 
  if( ID())
  {
    comma(9);
    while(1)
    {
      if(Serial.available())
      {
        alt[i] = Serial.read();
        if(alt[i]==',')
          flag=1;
        else
          i++;
      }
      if(flag)
      {
        i=0;
        Serial.println(Datatransfer(alt,1),1);//print altitude data
        return;
      }  
    }
  }
}

//--------------------------------
//functions made by me
//--------------------------------
boolean EXPECT_COMMA = true;
boolean debug = false;
void grabSerialData(char* TimeRead, 
                    char* Latitude, char* LatDir, 
                    char* Longitude,  char* LongDir,
                    char* fixQuality){
  char i=0;
  char alt[8]={'0','0','0','0','0','0','0','0'};
  char value[6]={
    '$','G','P','G','G','A'    };//match the gps protocol
  char val[6]={
    '0','0','0','0','0','0'    };
 //this function is to grab all (or most) of the data
 //and put it in an array
  while(1)
  {
    if(Serial.available())
    {
      val[i] = Serial.read();//get the data from the serial interface
        
      if(val[i]==value[i]) //Match the protocol
      {    
        //if debug is enabled.
        debug = true;
        if(debug){Serial.print("Char:");Serial.println(val[i]);}
        i++;
        //if we found all of the letters in the protocol
        if(i==6)
        {
          Serial.println("Reading Time ...");
          readTillComma(TimeRead,EXPECT_COMMA);
          Serial.println("Reading Latitude ...");
          readTillComma(Latitude);
          Serial.println("Reading Latitude Dir...");
          readTillComma(LatDir);
          Serial.println("Reading Long ...");
          readTillComma(Longitude);
          Serial.println("Reading Long Dir...");
          readTillComma(LongDir);
          Serial.println("Reading Fix Qual ...");
          readTillComma(fixQuality);
          Serial.print("Time Read: ");  Serial.println(TimeRead);
          Serial.print("Latitude: ");   Serial.println(Latitude);
          Serial.print("LatDir: ");     Serial.println(LatDir);
          Serial.print("fixQuality: ");   Serial.println(fixQuality);
          return;//break out after get the command
        }
      }
      else
        i=0;
        
      //debug = false;
    }
  } 
}
//-------
//functions to read from serial interface
//at the beginning, the first char should be a comma
void extractTime(char* readBuff){
}
void extractLatitude(){
}
void extractLatDir(){
}
void extractLong(){
}
void extractLongDir(){
}
void readTillComma(char* readBuff, boolean expectingCommaFirst){
  char alt[8]={'0','0','0','0','0','0','0','0'};
  int i=0;
  while(1)
  {
    if(Serial.available())
    {
      alt[i] = Serial.read();
      if(debug){Serial.print("Char");Serial.print(i);Serial.print(" :");Serial.println(alt[i]);}
      //once a comma has been found
      if(alt[i]==','){
        Serial.println("Comma");
        //if i==0 and expectingCommaFirst=True; ignore it and keep going 
        //else if i==0 and expectingCommaFirst=False ; it means that there was nothing in this array, and return with error value
        if ((i==0) && (!expectingCommaFirst)){
          if(debug){Serial.println("Return with error");}
          readBuff[0] = '?';
          return;
        }
        //if i==1, then there was nothing between the first comma and this comma ; return with error value
        if((i==1) && (expectingCommaFirst)){
          if(debug){Serial.println("Return with error");}
          readBuff[0] = '?';
          return;
        }
        //if i>1; then return
        if( (i>1) ||
            ((i==1)&&(!expectingCommaFirst)))
          {if(debug){Serial.println("Return without error");}return;}
      }//end comma
      //if the character next is NOT a comma, save it in the readBuff char pointer
      else{
        Serial.println("Saving Char into buffer.");
        readBuff[i]=alt[i];
        i++;
      }
    }//end serial read
  }//end while
}
//--------------------------------
//setup and loop functions
void setupTest() //change to setup if you want to test out.
{
  pinMode(3,OUTPUT);//The default digital driver pins for the GSM and GPS mode
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  digitalWrite(5,HIGH);
  delay(1500);
  digitalWrite(5,LOW);
 
  digitalWrite(3,LOW);//Enable GSM mode
  digitalWrite(4,HIGH);//Disable GPS mode
  delay(2000);
  Serial.begin(9600); 
  delay(5000);//GPS ready
 
  Serial.println("AT");   
  delay(2000);
  //turn set baud rate to 9600
  Serial.println("AT+CGPSIPR=9600");
  delay(1000);
  //turn on GPS power supply
  Serial.println("AT+CGPSPWR=1");
  delay(1000);
  //reset GPS in autonomy mode
  Serial.println("AT+CGPSRST=1");
  delay(1000);
 
  digitalWrite(4,LOW);//Enable GPS mode
  digitalWrite(3,HIGH);//Disable GSM mode
  delay(2000);
 
  Serial.println("$GPGGA statement information: ");
}
void loopTest() //change to loop if want to test out
{
  while(1)
  { 
    char TimeRead  [50] = {0};
    char Latitude  [35] = {0};
    char LatDir  [2]    = {0};
    char Longitude [35] = {0};
    char LongDir [2]    = {0};
    char fixQuality [2] = {0};
    //grabbing the serial data from a single serial burst
    Serial.println("Reading Serial Data:");
    grabSerialData(TimeRead,   Latitude, LatDir, 
                   Longitude,  LongDir,
                   fixQuality);
    //i dont think any of these work anymore
    Serial.print("UTC:");
    UTC();
    Serial.print("Lat:");
    latitude();
    Serial.print("Dir:");
    lat_dir();
    Serial.print("Lon:");
    longitude();
    Serial.print("Dir:");
    lon_dir();
    Serial.print("Alt:");
    altitude();
    Serial.println(' ');
    Serial.println(' ');
    
    //grabSerialData();
  }
}
